﻿using MahApps.Metro.Controls;
using Microsoft.Win32;
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Threading;

namespace ServerGUI
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow
    {
        IEventCPP eventCPP;
        Bridge bridge;

        Process process_Server;
        BackgroundWorker process_Bridge;
        BackgroundWorker process_Tick;

        static ManualResetEvent manualResetEvent;

        int nClientSum = 0;

        class ClientInfo : INotifyPropertyChanged
        {
            string _name;
            string _ip;
            string _status;
            public int Id { get; set; }
            public string Name { get { return _name; } set { _name = value; OnPropertyChanged("Name"); } }
            public string Ip { get { return _ip; } set { _ip = value; OnPropertyChanged("Ip"); } }
            public string Status { get { return _status; } set { _status = value; OnPropertyChanged("Status"); } }

            public event PropertyChangedEventHandler PropertyChanged;
            private void OnPropertyChanged(string propertyName)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        AsyncObservableCollection<ClientInfo> ClientList { get; set; }
        
        class OSInfo
        {
            public string Name { get; set; }
            public string User { get; set; }
            public string OS { get; set; }
            public string Address { get; set; }
        }

        public MainWindow()
        {
            InitializeComponent();
            
            TB_OS.Text = (string)Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "ProductName", "")
                + (Environment.Is64BitOperatingSystem ? " x64 " : " x86 ") + Environment.OSVersion.Version.Major + "." + Environment.OSVersion.Version.Minor
                + "." + (string)Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "ReleaseId", "")
                + "." + (string)Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "CurrentBuild", "");

            ClientList = new AsyncObservableCollection<ClientInfo>();
            ListBox_Client.ItemsSource = ClientList;
            
            process_Tick = new BackgroundWorker();
            process_Tick.WorkerSupportsCancellation = true;
            process_Tick.DoWork += new DoWorkEventHandler(process_Tick_DoWork);
            process_Tick.RunWorkerAsync();
        }

        private void btn_Start_Click(object sender, RoutedEventArgs e)
        {
            if (eventCPP == null) eventCPP = new IEventCPP();
            eventCPP.onEnterEvent += new onRoomHandler(onEnter);
            eventCPP.onLeaveEvent += new onRoomHandler(onLeave);
            eventCPP.onChatEvent += new onChatHandler(onChat);
            if (bridge == null) bridge = new Bridge(eventCPP);

            if (process_Server == null) process_Server = new Process();
            process_Server.StartInfo.Arguments = "\"" + Environment.CurrentDirectory + "\\Server\\app.js\"";
            process_Server.StartInfo.CreateNoWindow = true;
            process_Server.StartInfo.FileName = "node.exe";
            process_Server.StartInfo.RedirectStandardError = true;
            process_Server.StartInfo.RedirectStandardInput = true;
            process_Server.StartInfo.RedirectStandardOutput = true;
            process_Server.StartInfo.UseShellExecute = false;
            process_Server.StartInfo.StandardOutputEncoding = Encoding.UTF8;
            process_Server.StartInfo.StandardErrorEncoding = Encoding.UTF8;
            process_Server.OutputDataReceived += new DataReceivedEventHandler(process_Server_OutputDataReceived);
            process_Server.ErrorDataReceived += new DataReceivedEventHandler(process_Server_ErrorDataReceived);
            process_Server.Exited += Process_Server_Exited;
            if (!process_Server.Start()) return;
            process_Server.BeginErrorReadLine();
            process_Server.BeginOutputReadLine();

            if (manualResetEvent == null) manualResetEvent = new ManualResetEvent(false);
            manualResetEvent.Set();

            if (process_Bridge == null) process_Bridge = new BackgroundWorker();
            process_Bridge.WorkerSupportsCancellation = true;
            process_Bridge.DoWork += new DoWorkEventHandler(process_Bridge_DoWork);
            process_Bridge.RunWorkerCompleted += new RunWorkerCompletedEventHandler(process_Bridge_RunWorkerCompleted);
            process_Bridge.RunWorkerAsync();

            btn_Start.IsEnabled = false;
            btn_Stop.IsEnabled = true;
            
            RTB_Text.Inlines.Add(new Run("启动服务端\n") { Foreground = Brushes.Red });
            RTB_Info.ScrollToEnd();
        }

        private void btn_Stop_Click(object sender, RoutedEventArgs e)
        {
            process_Bridge.CancelAsync();
        }

        private void process_Tick_DoWork(object sender, DoWorkEventArgs e)
        {
            while (!process_Tick.CancellationPending)
            {
                Action action = () =>
                {
                    TimeSpan timespan = new TimeSpan(Convert.ToInt64(Environment.TickCount) * 10000);
                    TB_TickCount.Text = timespan.Days + "天 " + timespan.Hours + "小时 " + timespan.Minutes + "分钟 " + timespan.Seconds + "秒 ";
                };
                if (Thread.CurrentThread != TB_TickCount.Dispatcher.Thread) TB_TickCount.Dispatcher.Invoke(DispatcherPriority.Normal, action);
                else action();
            }
        }
        private void Process_Server_Exited(object sender, EventArgs e)
        {
            btn_Start.IsEnabled = true;
            btn_Stop.IsEnabled = false;
        }

        private void process_Server_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (e.Data == null) return;

            Action action = () =>
            {
                RTB_Text.Inlines.Add(new Run(e.Data + "\n") { Foreground = Brushes.White });
                RTB_Info.Document.PageWidth = RTB_Text.Inlines.LastInline.FontSize * e.Data.Length;
                RTB_Info.ScrollToEnd();
            };
            if (Thread.CurrentThread != RTB_Info.Dispatcher.Thread) RTB_Info.Dispatcher.Invoke(DispatcherPriority.Normal, action);
            else action();
        }

        private void process_Server_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (e.Data == null) return;

            Action action = () =>
            {
                RTB_Text.Inlines.Add(new Run(e.Data + "\n") { Foreground = Brushes.Red });
                RTB_Info.Document.PageWidth = RTB_Text.Inlines.LastInline.FontSize * e.Data.Length;
                RTB_Info.ScrollToEnd();
            };
            if (Thread.CurrentThread != RTB_Info.Dispatcher.Thread) RTB_Info.Dispatcher.Invoke(DispatcherPriority.Normal, action);
            else action();
        }

        private void process_Bridge_DoWork(object sender, DoWorkEventArgs e)
        {
            while (!process_Bridge.CancellationPending)
            {
                bridge.Loop();
                manualResetEvent.WaitOne();
            }
        }

        private void process_Bridge_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (!process_Server.HasExited)
            {
                process_Server.Kill();
                process_Server.Close();
            }

            Action action = () =>
            {
                RTB_Text.Inlines.Add(new Run("关闭服务端\n") { Foreground = Brushes.Red });
                RTB_Info.ScrollToEnd();

                nClientSum = 0;
                RB_Clients.Text = nClientSum.ToString();

                for (var n = 0; n != ClientList.Count; n++) ClientList[n].Status = "未知";

                btn_Start.IsEnabled = true;
                btn_Stop.IsEnabled = false;
            };
            if (Thread.CurrentThread != RTB_Info.Dispatcher.Thread) RTB_Info.Dispatcher.Invoke(DispatcherPriority.Normal, action);
            else action();

            process_Server.Dispose();
            process_Server = null;
            process_Bridge.Dispose();
            process_Bridge = null;
        }

        private void onEnter(string msg)
        {
//             UTF8Encoding utf8 = new UTF8Encoding();
//             Byte[] encodedBytes = utf8.GetBytes(msg);
//             String decodedString = utf8.GetString(encodedBytes);

            Action action = () =>
            {
                nClientSum = nClientSum + 1;
                RB_Clients.Text = nClientSum.ToString();
            };
            if (Thread.CurrentThread != RB_Clients.Dispatcher.Thread) RB_Clients.Dispatcher.Invoke(DispatcherPriority.Normal, action);
            else action();

            var query = from kvp in ClientList
                        where kvp.Name == msg
                        select kvp.Id;
            if (query.Count() != 0) ClientList[query.FirstOrDefault() - 1].Status = "在线";
            else ClientList.Add(new ClientInfo() { Id = nClientSum, Name = msg, Ip = "", Status = "在线" });
        }

        private void onLeave(string msg)
        {
//             UTF8Encoding utf8 = new UTF8Encoding();
//             Byte[] encodedBytes = utf8.GetBytes(msg);
//             String decodedString = utf8.GetString(encodedBytes);

            Action action = () =>
            {
                nClientSum = nClientSum - 1;
                RB_Clients.Text = nClientSum.ToString();
            };
            if (Thread.CurrentThread != RB_Clients.Dispatcher.Thread) RB_Clients.Dispatcher.Invoke(DispatcherPriority.Normal, action);
            else action();

            var query = from kvp in ClientList
                        where kvp.Name == msg
                        select kvp.Id;
            if (query.Count() != 0) ClientList[query.FirstOrDefault() - 1].Status = "离线";
        }

        private void onChat(string user, string msg)
        {
            Action action = () =>
            {
                RTB_Text.Inlines.Add(new Run(user + "：" + msg + "\n") { Foreground = Brushes.Red });
                RTB_Info.Document.PageWidth = RTB_Text.Inlines.LastInline.FontWeight.ToOpenTypeWeight() * 10;
                RTB_Info.ScrollToEnd();

                ParseMsg(msg);
            };
            if (Thread.CurrentThread != RTB_Info.Dispatcher.Thread) RTB_Info.Dispatcher.Invoke(DispatcherPriority.Normal, action);
            else action();
        }

        private void ListBox_Client_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            ClientInfo info = (ClientInfo)ListBox_Client.SelectedItem;
//             if (info == null) return;
            var flyout = Flyouts.Items[0] as Flyout;
            flyout.IsOpen = !flyout.IsOpen;
        }

        private void ParseMsg(string msg)
        {
            string[] content = msg.Split(new Char[] { ':' }, 2);

            switch(content[0])
            {
                case "sysinfo":
                    OSInfo osinfo = JsonHelper.DeserializeJsonToObject<OSInfo>(content[1]);
                    ClientName.Text = "名称：" + osinfo.Name;
                    ClientUser.Text = "用户：" + osinfo.User;
                    ClientOS.Text = "操作系统：" + osinfo.OS;
                    ClientIp.Text = "IP：" + osinfo.Address;
                    break;
            }
        }

        private void btn_ShowMessagebox_Click(object sender, RoutedEventArgs e)
        {
            string target = ClientList[ListBox_Client.SelectedIndex].Name;
            manualResetEvent.Reset();
            bridge.SendMsg("Messagebox:收到服务端发送的消息", target);
            manualResetEvent.Set();
        }

        private void MetroWindow_Closed(object sender, EventArgs e)
        {
            if (process_Bridge != null && process_Bridge.IsBusy)
                process_Bridge.CancelAsync();
        }
    }
}
